package org.mspring.platform.dao.hibernate;

import java.io.Serializable;
import java.util.List;

import org.apache.commons.lang3.ClassUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.mspring.platform.dao.Page;
import org.mspring.platform.dao.hibernate.common.CriteriaQuery;
import org.mspring.platform.dao.hibernate.common.EnhancedRule;
import org.mspring.platform.dao.query.QueryBuilder;
import org.mspring.platform.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate4.HibernateTemplate;

/**
 *
 * @author Gao Youbo
 * @since 2014年5月14日
 */
@SuppressWarnings("unchecked")
public class DefaultHibernateTemplate extends HibernateTemplate {

    private static final Logger log = LoggerFactory.getLogger(DefaultHibernateTemplate.class);

    private JdbcTemplate jdbcTemplate;

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     *
     * @param entityClass
     * @return
     */
    public List<?> listAll(Class<?> entityClass) {
        String alias = "_" + entityClass.getSimpleName();
        StringBuilder sb = new StringBuilder();
        sb.append("select ");
        sb.append(alias);
        sb.append(" from ");
        sb.append(entityClass.getName());
        sb.append(" ").append(alias);
        return this.find(sb.toString());
    }

    public List<?> list(Class<?> entityClass, EnhancedRule enhancedRule) {
        if (enhancedRule == null) {
            return listAll(entityClass);
        }
        return enhancedRule.getCriteria(entityClass, getSession()).list();
    }

    public List<?> list(String hql, Object... params) {
        Query query = getQueryByHQL(hql);
        if (params != null && params.length > 0) {
            HibernateUtils.setParameters(query, params);
        }
        return query.list();
    }

    public List<?> list(CriteriaQuery criteriaQuery) {
        Criteria criteria = criteriaQuery.getCriteria(this.getSession());
        return criteria.list();
    }

    public <T> List<T> list(QueryBuilder queryBuilder) {
        Query query = getQueryByHQL(queryBuilder.getQueryString());
        HibernateUtils.applyQueryBuilderToQuery(query, queryBuilder);
        return query.list();
    }

    public <T> T getBy(Class<T> entityClass, String property, Object value) {
        EnhancedRule rule = new EnhancedRule();
        rule.add(Restrictions.eq(property, value));
        return (T) rule.getCriteria(entityClass, getSession()).uniqueResult();
    }

    public <T> T uniqueResult(String hql, Object... params) {
        List<?> list = find(hql, params);
        if (list == null || list.isEmpty()) {
            return null;
        }
        return (T) list.get(0);
    }

    public int executeUpdate(String hql, Object... params) {
        Query query = getQueryByHQL(hql);
        if (params != null && params.length > 0) {
            HibernateUtils.setParameters(query, params);
        }
        return query.executeUpdate();
    }

    public int executeUpdate(String hql, String[] names, Object[] params) {
        return HibernateUtils.setParameters(getQueryByHQL(hql), names, params).executeUpdate();
    }

    public void delete(Class<?> entityClass, Serializable... id) {
        if (id == null || id.length == 0) {
            return;
        }
        Session session = getSession();
        for (Serializable s : id) {
            Object object = session.load(entityClass, s);
            session.delete(object);
        }
    }

    public Page<?> listPage(Class<?> entityClass, Page<?> page) {
        String alias = "_" + StringUtils.uncapitalize(ClassUtils.getShortClassName(entityClass));
        String queryString = HibernateUtils.applyPaginationSorter(page, "from " + entityClass.getName() + " " + alias);
        Query queryObject = getQueryByHQL(queryString);
        if (page.isAutoCount()) {
            int count = count(HibernateUtils.getCountHQL(queryString));
            page.setTotalCount(count);
            page.setAutoCount(false);
        }
        HibernateUtils.applyPagination(page, queryObject);
        page.setResult(queryObject.list());
        return page;
    }

    public <T> Page<T> listPage(QueryBuilder queryBuilder, Page<T> page) {
        String queryString = HibernateUtils.applyPaginationSorter(page, queryBuilder.getQueryString()); // 处理排序字段
        Session session = getSession();
        Query queryObject = session.createQuery(queryString);
        Query countObject = session.createQuery(queryBuilder.getCountString());
        HibernateUtils.applyQueryBuilderToQuery(queryObject, queryBuilder); // 处理查询条件
        HibernateUtils.applyQueryBuilderToQuery(countObject, queryBuilder); // 处理查询条件
        if (page.isAutoCount()) {
            int count = HibernateUtils.getCount(countObject.uniqueResult());
            page.setTotalCount(count);
            page.setAutoCount(false);
        }
        HibernateUtils.applyPagination(page, queryObject);
        page.setResult(queryObject.list());
        return page;
    }

    public <T> Page<T> listPage(String queryString, Page<T> page, Object... params) {
        String queryStringValue = HibernateUtils.applyPaginationSorter(page, queryString);
        Query queryObject = HibernateUtils.setParameters(getQueryByHQL(queryStringValue), params);
        if (page.isAutoCount()) {
            Query countQuery = HibernateUtils.setParameters(getQueryByHQL(HibernateUtils.getCountHQL(queryString)), params);
            int count = HibernateUtils.getCount(countQuery.uniqueResult());
            page.setTotalCount(count);
            page.setAutoCount(false);
        }
        HibernateUtils.applyPagination(page, queryObject);
        page.setResult(queryObject.list());
        return page;
    }

    public <T> Page<T> listPage(CriteriaQuery criteriaQuery, Page<T> page) {
        Session session = getSession();
        criteriaQuery.setFirstResult(page.getFirst());
        criteriaQuery.setMaxResults(page.getPageSize());
        if (page.isAutoCount()) {
            Criteria countCriteria = criteriaQuery.getCountCriteria(session);
            Object object = countCriteria.uniqueResult();
            int count = Integer.valueOf(object.toString());
            page.setTotalCount(count);
            page.setAutoCount(false);
        }
        page.setResult(criteriaQuery.getCriteria(session).list());
        return page;
    }

    public int count(String hql, Object... params) {
        Object obj = uniqueResult(hql, params);
        return HibernateUtils.getCount(obj);
    }

    public int count(Class<?> entityClass, EnhancedRule enhancedRule) {
        if (enhancedRule == null) {
            return 0;
        }
        Object obj = enhancedRule.getCountCriteria(entityClass, getSession()).uniqueResult();
        if (obj == null) {
            return 0;
        }
        return Integer.parseInt(obj.toString());
    }

    public Long queryForLong(String hql, Object... params) {
        Object obj = uniqueResult(hql, params);
        if (obj == null) {
            return null;
        }
        return Long.valueOf(obj.toString());
    }

    public Session getSession() {
        Session session = null;
        try {
            session = getSessionFactory().getCurrentSession();
        } catch (Exception e) {
            log.error("无法获取session", e);
        }
        return session;
    }

    protected Query getQueryByHQL(String hql) {
        return getSession().createQuery(hql);
    }

}
